1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.hash;
16
17 import static com.google.common.base.Preconditions.checkArgument;
18
19 import com.google.common.base.Preconditions;
20
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import java.nio.charset.Charset;
24
25
26
27
28
29
30
31
32
33
34
35 abstract class AbstractStreamingHashFunction implements HashFunction {
36 @Override public <T> HashCode hashObject(T instance, Funnel<? super T> funnel) {
37 return newHasher().putObject(instance, funnel).hash();
38 }
39
40 @Override public HashCode hashUnencodedChars(CharSequence input) {
41 return newHasher().putUnencodedChars(input).hash();
42 }
43
44 @Override public HashCode hashString(CharSequence input, Charset charset) {
45 return newHasher().putString(input, charset).hash();
46 }
47
48 @Override public HashCode hashInt(int input) {
49 return newHasher().putInt(input).hash();
50 }
51
52 @Override public HashCode hashLong(long input) {
53 return newHasher().putLong(input).hash();
54 }
55
56 @Override public HashCode hashBytes(byte[] input) {
57 return newHasher().putBytes(input).hash();
58 }
59
60 @Override public HashCode hashBytes(byte[] input, int off, int len) {
61 return newHasher().putBytes(input, off, len).hash();
62 }
63
64 @Override public Hasher newHasher(int expectedInputSize) {
65 Preconditions.checkArgument(expectedInputSize >= 0);
66 return newHasher();
67 }
68
69
70
71
72
73
74
75
76
77 protected static abstract class AbstractStreamingHasher extends AbstractHasher {
78
79 private final ByteBuffer buffer;
80
81
82 private final int bufferSize;
83
84
85 private final int chunkSize;
86
87
88
89
90
91
92
93
94 protected AbstractStreamingHasher(int chunkSize) {
95 this(chunkSize, chunkSize);
96 }
97
98
99
100
101
102
103
104
105
106
107 protected AbstractStreamingHasher(int chunkSize, int bufferSize) {
108
109 checkArgument(bufferSize % chunkSize == 0);
110
111
112 this.buffer = ByteBuffer
113 .allocate(bufferSize + 7)
114 .order(ByteOrder.LITTLE_ENDIAN);
115 this.bufferSize = bufferSize;
116 this.chunkSize = chunkSize;
117 }
118
119
120
121
122 protected abstract void process(ByteBuffer bb);
123
124
125
126
127
128
129
130
131
132 protected void processRemaining(ByteBuffer bb) {
133 bb.position(bb.limit());
134 bb.limit(chunkSize + 7);
135 while (bb.position() < chunkSize) {
136 bb.putLong(0);
137 }
138 bb.limit(chunkSize);
139 bb.flip();
140 process(bb);
141 }
142
143 @Override
144 public final Hasher putBytes(byte[] bytes) {
145 return putBytes(bytes, 0, bytes.length);
146 }
147
148 @Override
149 public final Hasher putBytes(byte[] bytes, int off, int len) {
150 return putBytes(ByteBuffer.wrap(bytes, off, len).order(ByteOrder.LITTLE_ENDIAN));
151 }
152
153 private Hasher putBytes(ByteBuffer readBuffer) {
154
155 if (readBuffer.remaining() <= buffer.remaining()) {
156 buffer.put(readBuffer);
157 munchIfFull();
158 return this;
159 }
160
161
162 int bytesToCopy = bufferSize - buffer.position();
163 for (int i = 0; i < bytesToCopy; i++) {
164 buffer.put(readBuffer.get());
165 }
166 munch();
167
168
169 while (readBuffer.remaining() >= chunkSize) {
170 process(readBuffer);
171 }
172
173
174 buffer.put(readBuffer);
175 return this;
176 }
177
178 @Override
179 public final Hasher putUnencodedChars(CharSequence charSequence) {
180 for (int i = 0; i < charSequence.length(); i++) {
181 putChar(charSequence.charAt(i));
182 }
183 return this;
184 }
185
186 @Override
187 public final Hasher putByte(byte b) {
188 buffer.put(b);
189 munchIfFull();
190 return this;
191 }
192
193 @Override
194 public final Hasher putShort(short s) {
195 buffer.putShort(s);
196 munchIfFull();
197 return this;
198 }
199
200 @Override
201 public final Hasher putChar(char c) {
202 buffer.putChar(c);
203 munchIfFull();
204 return this;
205 }
206
207 @Override
208 public final Hasher putInt(int i) {
209 buffer.putInt(i);
210 munchIfFull();
211 return this;
212 }
213
214 @Override
215 public final Hasher putLong(long l) {
216 buffer.putLong(l);
217 munchIfFull();
218 return this;
219 }
220
221 @Override
222 public final <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
223 funnel.funnel(instance, this);
224 return this;
225 }
226
227 @Override
228 public final HashCode hash() {
229 munch();
230 buffer.flip();
231 if (buffer.remaining() > 0) {
232 processRemaining(buffer);
233 }
234 return makeHash();
235 }
236
237 abstract HashCode makeHash();
238
239
240 private void munchIfFull() {
241 if (buffer.remaining() < 8) {
242
243 munch();
244 }
245 }
246
247 private void munch() {
248 buffer.flip();
249 while (buffer.remaining() >= chunkSize) {
250
251
252 process(buffer);
253 }
254 buffer.compact();
255 }
256 }
257 }